from datetime import datetime

class TaskNode:
    """Represents a node in the Hierarchical Task Network"""
    def __init__(self, task_id, task_type, description):
        self.task_id = task_id
        self.task_type = task_type  # 'primitive' or 'compound'
        self.description = description
        self.subtasks = []
        self.cost_factors = {
            'resource': 0.0,  # R(t) - resource requirements
            'time': 0.0,      # T(t) - estimated time
            'risk': 0.0,      # F(t) - failure risk
            'importance': 1.0  # w_i - task importance weight
        }
    
    def add_subtask(self, subtask):
        self.subtasks.append(subtask)
    
    def calculate_total_cost(self):
        return sum(w * f for f, w in self.cost_factors.items())

class HierarchicalPlanner:
    """HTN-based planning implementation"""
    def __init__(self):
        self.task_library = {}
        
    def decompose_task(self, high_level_task):
        if high_level_task.task_type == 'primitive':
            return [high_level_task]
            
        primitive_tasks = []
        for subtask in high_level_task.subtasks:
            primitive_tasks.extend(self.decompose_task(subtask))
        return primitive_tasks
    
    def calculate_cost(self, task):
        if task.task_type == 'primitive':
            return task.calculate_total_cost()
        return sum(self.calculate_cost(subtask) for subtask in task.subtasks)

class PlanningSpace:
    """Planning Space implementation (Section 3.2)"""
    def __init__(self):
        self.memory = []
        self.planning_params = {
            "min_confidence": 0.6,
            "max_depth": 3,
            "timeout": 30  # seconds
        }

    def create_analysis_plan(self, perception, aspects=None):
        """Create analysis plan based on perception
        Note: This function name might be refactored in future versions
        
        Args:
            perception: Dict containing perception results
            aspects: List of aspects to analyze, e.g., ["color_harmony", "composition"]
            
        Returns:
            dict: Analysis plan containing:
                - steps: List of analysis steps
                - priorities: Priority for each step
                - constraints: Any constraints to consider
        """
        if aspects is None:
            aspects = ["color_harmony", "composition", "style_coherence"]
            
        # Create analysis steps
        analysis_steps = []
        for aspect in aspects:
            step = {
                "type": aspect,
                "priority": self._get_aspect_priority(aspect),
                "required_features": self._get_required_features(aspect),
                "success_criteria": self._get_success_criteria(aspect)
            }
            analysis_steps.append(step)
            
        # Sort steps by priority
        analysis_steps.sort(key=lambda x: x["priority"], reverse=True)
        
        # Create complete plan
        plan = {
            "steps": analysis_steps,
            "constraints": {
                "time_limit": self.planning_params["timeout"],
                "min_confidence": self.planning_params["min_confidence"]
            },
            "context": {
                "perception_quality": self._assess_perception_quality(perception),
                "available_features": list(perception.keys())
            }
        }
        
        # Store in memory
        self.memory.append(plan)
        
        return plan

    def _get_aspect_priority(self, aspect):
        """Get priority level for analysis aspect"""
        priorities = {
            "color_harmony": 0.9,
            "composition": 0.8,
            "style_coherence": 0.7,
            "trend_alignment": 0.6
        }
        return priorities.get(aspect, 0.5)

    def _get_required_features(self, aspect):
        """Get required features for each analysis aspect"""
        feature_map = {
            "color_harmony": ["color_features", "deep_features"],
            "composition": ["spatial_features", "semantic_features"],
            "style_coherence": ["deep_features", "semantic_features"],
            "trend_alignment": ["semantic_features"]
        }
        return feature_map.get(aspect, [])

    def _get_success_criteria(self, aspect):
        """Define success criteria for each aspect"""
        return {
            "min_confidence": 0.7,
            "required_evidence": 3,
            "max_uncertainty": 0.3
        }

    def _assess_perception_quality(self, perception):
        """Assess quality of perception results"""
        if not perception:
            return 0.0
            
        # Check feature availability
        available_features = set(perception.keys())
        required_features = {"deep_features", "spatial_features", "semantic_features"}
        
        completeness = len(available_features & required_features) / len(required_features)
        
        return completeness

class Task:
    """Task representation in planning space"""
    def __init__(self, id, type, description, cost_factors):
        self.id = id
        self.type = type  # 'primitive' or 'compound'
        self.description = description
        self.subtasks = []
        self.cost_factors = cost_factors 